using Engine;
using Game;
using GameEntitySystem;
using TemplatesDatabase;
using Random = Game.Random;

namespace SCIENEW {
    public class ComponentHearthFurnace : ComponentInventoryTankBase, IUpdateable {
        public ComponentBlockEntity m_componentBlockEntity;
        public SubsystemTerrain m_subsystemTerrain;
        public SubsystemTime m_subsystemTime;
        public SubsystemExplosions m_subsystemExplosions;
        public SubsystemFluidTransfer m_subsystemFluidTransfer;

        public ComponentFireBox[] m_componentFireBox = new ComponentFireBox[2];//燃烧室
        public ComponentAirBlower[] m_componentAirBlower = new ComponentAirBlower[2];

        public Dictionary<Point3, int> m_ports = new();

        public UpdateOrder UpdateOrder => UpdateOrder.Default;
        public bool IsIntegrity { get; private set; } = false;
        public bool IsWorking => IsIntegrity && m_componentAirBlower.All(x => x != null && x.IsWorking()) && m_componentFireBox.All(x => x != null && x.IsPreheating());
        public int MoltenIronTankIndex => 0;
        public int MoltenSteelTankIndex => 1;

        public float SmeltingSpeed = 1f;

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap) {
            base.Load(valuesDictionary, idToEntityMap);
            m_componentBlockEntity = Entity.FindComponent<ComponentBlockEntity>(true);
            m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
            m_subsystemTime = Project.FindSubsystem<SubsystemTime>(true);
            m_subsystemExplosions = Project.FindSubsystem<SubsystemExplosions>(true);
            m_subsystemFluidTransfer = Project.FindSubsystem<SubsystemFluidTransfer>(true);

            UpdateVolume();
        }

        public override int GetSlotCapacity(int slotIndex, int value) => Terrain.ExtractContents(value) == BaseItemBlock.Index && ItemsBlockManager.GetItemCraftingID(value) == "CokeCoalPowder" ? base.GetSlotCapacity(slotIndex, value) : 0;

        public override float GetTankCapacity(int tankIndex, int value) {
            if (tankIndex == MoltenIronTankIndex
                && FluidsManager.GetFluid(value) is MoltenMetalFluid moltenMetalFluid
                && moltenMetalFluid.GetMaterial() == Materials.Iron) {
                return base.GetTankCapacity(tankIndex, value);
            }
            if (tankIndex == MoltenSteelTankIndex
                && FluidsManager.GetFluid(value) is MoltenMetalFluid moltenMetalFluid2
                && moltenMetalFluid2.GetMaterial() == Materials.Steel) {
                return base.GetTankCapacity(tankIndex, value);
            }
            return 0;
        }

        public void Update(float dt) {
            TerrainChunk chunkAtCell = m_subsystemTerrain.Terrain.GetChunkAtCell(m_componentBlockEntity.Coordinates.X, m_componentBlockEntity.Coordinates.Z);
            if (chunkAtCell != null
                && chunkAtCell.State is TerrainChunkState.Valid or TerrainChunkState.InvalidLight or TerrainChunkState.InvalidPropagatedLight) {
                if (m_subsystemTime.PeriodicGameTimeEvent(0.2f, 0.0f)) {//一秒5次检测
                    CheckIntegrity();
                }
            }
            ReplaceFurnace(m_componentBlockEntity.Coordinates);
            UpdateSmelting(dt);
        }

        public override void OnEntityRemoved() {
            base.OnEntityRemoved();
            foreach (var port in m_ports) {
                if (m_subsystemFluidTransfer.m_elements.TryGetValue(port.Key, out FluidTransferrer? value) && value is HearthFurnaceInputPortTransferrer inputPort)
                    inputPort.ResetHearthFurnace();
                else if (m_subsystemFluidTransfer.m_elements.TryGetValue(port.Key, out FluidTransferrer? value2) && value2 is HearthFurnaceOutputPortTransferrer outputPort)
                    outputPort.ResetHearthFurnace();
            }
            m_ports.Clear();
        }

        void UpdateSmelting(float dt) {
            float removingVolume = SmeltingSpeed * dt;
            int moltenSteelID = FluidsManager.GetFluidIDByMaterial<MoltenMetalFluid>(Materials.Steel);
            bool haveMetal = m_slots.Any(x => x.Count > 0) && GetTankVolume(MoltenIronTankIndex) > 0;
            bool isFull = GetTankVolume(MoltenSteelTankIndex) + removingVolume >= GetTankCapacity(MoltenSteelTankIndex, moltenSteelID);
            if (IsWorking && haveMetal && !isFull) {
                float removedIronVolume = RemoveTankFluid(MoltenIronTankIndex, removingVolume);
                AddTankFluid(MoltenSteelTankIndex, moltenSteelID, removedIronVolume, out float overflow);
                if (m_subsystemTime.PeriodicGameTimeEvent(4, 0.0f)) {
                    Slot[] catsSlots = m_slots.Where(x => x.Count > 0).ToArray();
                    if (catsSlots.Length > 0) {//有催化剂
                        int catIndex = new Random().Int(0, catsSlots.Length - 1);
                        catsSlots[catIndex].Count--;
                    }
                }
            }
        }

        void CheckIntegrity() {
            foreach (var port in m_ports) {
                if (m_subsystemFluidTransfer.m_elements.TryGetValue(port.Key, out FluidTransferrer? value) && value is HearthFurnaceInputPortTransferrer inputPort)
                    inputPort.ResetHearthFurnace();
                else if (m_subsystemFluidTransfer.m_elements.TryGetValue(port.Key, out FluidTransferrer? value2) && value2 is HearthFurnaceOutputPortTransferrer outputPort)
                    outputPort.ResetHearthFurnace();
            }
            m_ports.Clear();
            m_componentFireBox = new ComponentFireBox[2];
            m_componentAirBlower = new ComponentAirBlower[2];

            Point3 corePos = m_componentBlockEntity.Coordinates;
            int coreValue = m_subsystemTerrain.Terrain.GetCellValueFast(corePos.X, corePos.Y, corePos.Z);
            int face = IlluminableDevice.GetDirection_Static(coreValue);//核心朝向
            Point3 centerPos = corePos - CellFace.FaceToPoint3(face);//结构中心的坐标

            //第一层
            for (int x = -1; x <= 1; x++) {
                for (int z = -1; z <= 1; z++) {//检测3*3耐火砖
                    Point3 testPos = centerPos + new Point3(x, -1, z);
                    if (CheckFireBrick(testPos.X, testPos.Y, testPos.Z)) { continue; }//检测到耐火砖，继续下一块
                    DeviceBlock? deviceBlock = DevicesUtils.FindDevice(m_subsystemTerrain, testPos, out int testBlockValue);
                    if (deviceBlock is HearthFurnaceInputPortDevice) {
                        m_ports.Add(testPos, testBlockValue);
                        if (m_subsystemFluidTransfer.m_elements[testPos] is HearthFurnaceInputPortTransferrer hearthFurnaceInputPortTransferrer)
                            hearthFurnaceInputPortTransferrer.AssignHearthFurnace(this);
                        continue;
                    }
                    if (deviceBlock is HearthFurnaceOutputPortDevice) {
                        m_ports.Add(testPos, testBlockValue);
                        if (m_subsystemFluidTransfer.m_elements[testPos] is HearthFurnaceOutputPortTransferrer hearthFurnaceOutputPortTransferrer)
                            hearthFurnaceOutputPortTransferrer.AssignHearthFurnace(this);
                        continue;
                    }
                    //检测到非法方块，不成形
                    IsIntegrity = false;
                    return;
                }
            }
            int[] sideFaces = new int[2];//检测两侧空气预热炉
            DevicesUtils.GetSideFaceOfXZ(face, out sideFaces[0], out sideFaces[1]);
            Point3 fireBoxPos1 = centerPos - Point3.UnitY + CellFace.FaceToPoint3(sideFaces[0]) * 2;
            Point3 fireBoxPos2 = centerPos - Point3.UnitY + CellFace.FaceToPoint3(sideFaces[1]) * 2;
            bool fireBox1 = false, fireBox2 = false;
            if (DeviceEntityUtils.GetDeviceEntity(m_subsystemTerrain, fireBoxPos1, out ComponentBlockEntity fireBoxEntity)) {
                m_componentFireBox[0] = fireBoxEntity.Entity.FindComponent<ComponentFireBox>();
                if (m_componentFireBox[0] != null) {
                    fireBox1 = true;
                }
            }
            if (DeviceEntityUtils.GetDeviceEntity(m_subsystemTerrain, fireBoxPos2, out ComponentBlockEntity fireBoxEntity2)) {
                m_componentFireBox[1] = fireBoxEntity2.Entity.FindComponent<ComponentFireBox>();
                if (m_componentFireBox[1] != null) {
                    fireBox2 = true;
                }
            }
            if (!fireBox1
                || !fireBox2) {
                //检测到有一方没有燃烧室，不成形
                IsIntegrity = false;
                return;
            }

            //第二层
            Point3 backPoint = centerPos - CellFace.FaceToPoint3(face);//核心背对的面
            Point3 rightPoint = centerPos + CellFace.FaceToPoint3(sideFaces[0]);//鼓风机背对的面
            Point3 leftPoint = centerPos + CellFace.FaceToPoint3(sideFaces[1]);//鼓风机正对的面
            bool center = m_subsystemTerrain.Terrain.GetCellContentsFast(centerPos.X, centerPos.Y, centerPos.Z) is AirBlock.Index;
            bool corner1 = CheckSteelBlock(centerPos.X - 1, centerPos.Y, centerPos.Z - 1);//检测四个角
            bool corner2 = CheckSteelBlock(centerPos.X - 1, centerPos.Y, centerPos.Z + 1);
            bool corner3 = CheckSteelBlock(centerPos.X + 1, centerPos.Y, centerPos.Z + 1);
            bool corner4 = CheckSteelBlock(centerPos.X + 1, centerPos.Y, centerPos.Z - 1);
            bool back = CheckSteelBlock(backPoint.X, backPoint.Y, backPoint.Z);
            bool right = m_subsystemTerrain.Terrain.GetCellContentsFast(rightPoint.X, rightPoint.Y, rightPoint.Z) is AirBlock.Index;
            bool left = m_subsystemTerrain.Terrain.GetCellContentsFast(leftPoint.X, leftPoint.Y, leftPoint.Z) is AirBlock.Index;
            if (!(center && corner1 && corner2 && corner3 && corner4 && back && right && left)) {//四个角不完全满足是砖块，未成形
                IsIntegrity = false;
                return;
            }
            Point3 airBlowerPos1 = centerPos + CellFace.FaceToPoint3(sideFaces[0]) * 2;
            Point3 airBlowerPos2 = centerPos + CellFace.FaceToPoint3(sideFaces[1]) * 2;
            bool airBlower1 = false, airBlower2 = false;
            if (DeviceEntityUtils.GetDeviceEntity(m_subsystemTerrain, airBlowerPos1, out ComponentBlockEntity airBlowerEntity)) {
                m_componentAirBlower[0] = airBlowerEntity.Entity.FindComponent<ComponentAirBlower>();
                if (m_componentAirBlower[0] != null) {
                    airBlower1 = true;
                }
            }
            if (DeviceEntityUtils.GetDeviceEntity(m_subsystemTerrain, airBlowerPos2, out ComponentBlockEntity airBlowerEntity2)) {
                m_componentAirBlower[1] = airBlowerEntity2.Entity.FindComponent<ComponentAirBlower>();
                if (m_componentAirBlower[1] != null) {
                    airBlower2 = true;
                }
            }
            if (!airBlower1
                || !airBlower2) {
                //检测到有一方没有鼓风机，不成形
                IsIntegrity = false;
                return;
            }

            //第三层
            for (int x = -1; x <= 1; x++) {
                for (int z = -1; z <= 1; z++) {//检测3*3钢块
                    Point3 testPos = centerPos + new Point3(x, 1, z);
                    if (CheckSteelBlock(testPos.X, testPos.Y, testPos.Z)) { continue; }//检测到钢块，继续下一块
                    //检测到非法方块，不成形
                    IsIntegrity = false;
                    return;
                }
            }

            //检测流程下来没有任何不符，已成型
            IsIntegrity = true;

            bool CheckFireBrick(int x, int y, int z) {
                int blockValue = m_subsystemTerrain.Terrain.GetCellValueFast(x, y, z);
                return Terrain.ExtractContents(blockValue) == BaseNormalBlock.Index && NormalBlockManager.GetNormalBlock(blockValue).GetCraftingId() == "FirebrickWall";
            }
            bool CheckSteelBlock(int x, int y, int z) {
                int blockValue = m_subsystemTerrain.Terrain.GetCellValueFast(x, y, z);
                return Terrain.ExtractContents(blockValue) == BaseNormalBlock.Index && NormalBlockManager.GetNormalBlock(blockValue) is MetalNBlock metalNBlock && metalNBlock.GetMaterial() == Materials.Steel;
            }
        }

        void UpdateVolume() {
            m_tanks[MoltenIronTankIndex].Capacity = 3 * 36f;
            m_tanks[MoltenIronTankIndex].Volume = MathUtils.Min(m_tanks[MoltenIronTankIndex].Volume, m_tanks[MoltenIronTankIndex].Capacity);
            m_tanks[MoltenSteelTankIndex].Capacity = 3 * 36f;
            m_tanks[MoltenSteelTankIndex].Volume = MathUtils.Min(m_tanks[MoltenSteelTankIndex].Volume, m_tanks[MoltenSteelTankIndex].Capacity);
        }

        void ReplaceFurnace(Point3 coordinates) {
            TerrainChunk chunkAtCell = m_subsystemTerrain.Terrain.GetChunkAtCell(coordinates.X, coordinates.Z);
            if (chunkAtCell != null
                && chunkAtCell.State == TerrainChunkState.Valid) {
                int cellValue = m_subsystemTerrain.Terrain.GetCellValue(coordinates.X, coordinates.Y, coordinates.Z);
                int direction = IlluminableDevice.GetDirection_Static(cellValue);
                int deviceValue = DevicesBlockManager.GetDeviceValueByType(typeof(OpenHearthFurnaceDevice), IsWorking ? 0b100 | direction : direction);
                m_subsystemTerrain.ChangeCell(coordinates.X, coordinates.Y, coordinates.Z, deviceValue);
            }
        }
    }
}